﻿using System;
using System.Collections.Generic;
using System.Linq;
using DLM.Domain.Model;
using DLM.Domain.DTO;
using DLM.Domain.Repositories;
using DLM.Infrastructure.UnitOfWork;
using Webdiyer.WebControls.Mvc;

namespace DLM.Data.EF.CodeFirst.Repositories
{
    public class UserRepository : Repository<User, int>, IUserRepository
    {
        public UserRepository(IUnitOfWork unitOfWork)
            : base(unitOfWork)
        {

        }

        public new System.Collections.IEnumerator GetEnumerator()
        {
            throw new NotImplementedException();
        }

        public User FindByName(string userName)
        {
            if (string.IsNullOrEmpty(userName))
            {
                throw new ArgumentNullException("User name cannot be null!");
            }
            return this.ActiveContext.User.FirstOrDefault(u => u.AccountName == userName);
        }


        public User FindByAccount(int accountID)
        {
            if (accountID < 0)
            {
                throw new ArgumentNullException("Account id cannot be null!");
            }
            return this.ActiveContext.User.FirstOrDefault(u => u.AccountID == accountID);
        }


        public IEnumerable<User> FindByParty(int partyID, int count)
        {
            if (partyID < 0)
            {
                throw new ArgumentOutOfRangeException("Id cannot be negative!");
            }
            var result = from p in this.ActiveContext.Party
                         join uap in this.ActiveContext.UserPartyAssociation
                         on p.PartyID equals uap.PartyID
                         join u in this.ActiveContext.User
                         on uap.UserID equals u.UserID
                         select u;
            return result.Take(count).ToList();
        }


        public IEnumerable<User> FindByParty(int partyID, int pageIndex, int pageSize)
        {
            if (partyID < 0)
            {
                throw new ArgumentOutOfRangeException("Id cannot be negative!");
            }
            var result = from p in this.ActiveContext.Party
                         join uap in this.ActiveContext.UserPartyAssociation
                         on p.PartyID equals uap.PartyID
                         join u in this.ActiveContext.User
                         on uap.UserID equals u.UserID
                         select u;
            return result.OrderByDescending(u => u.CreateDate).ToPagedList(pageIndex, pageSize);
        }

        public IEnumerable<User> FindByParticipated(int partyID, int pageIndex, int pageSize)
        {
            if (partyID <= 0)
            {
                throw new ArgumentOutOfRangeException("Id cannot be negative!");
            }
            var result = from u in this.ActiveContext.User
                         join up in this.ActiveContext.UserPartyAssociation
                         on u.UserID equals up.UserID
                         where up.PartyID == partyID
                         select u;
            return result.OrderByDescending(u => u.CreateDate).ToPagedList(pageIndex, pageSize);
        }

        public IEnumerable<UserDTO> FindParticipatedDTO(int partyID)
        {
            if (partyID <= 0)
            {
                throw new ArgumentOutOfRangeException("Id cannot be negative!");
            }
            var result = from u in this.ActiveContext.User
                         join up in this.ActiveContext.UserPartyAssociation
                         on u.UserID equals up.UserID
                         where up.PartyID == partyID
                         select new UserDTO
                         {
                             UserID = u.UserID,
                             AccountID = u.AccountID,
                             AccountName = u.AccountName,
                             IsLead = up.IsLead,
                             EngagedDate = up.AssociationDate
                         };

            return result.OrderByDescending(u => u.EngagedDate).ToList();
        }

        public IEnumerable<Domain.DTO.BillBoard> BillBoard()
        {
            return this.ActiveContext.Database.SqlQuery<BillBoard>("select top 30 c.userid,c.accountname,c.name,c.photo,(cast(a.ParticipateCount as int) * 100 + cast(isnull(b.viewcount,0) as int)) rate " +
            " from (select count(partyid) as ParticipateCount,userid from dbo.UserPartyAssociation group by userid) as a left join " +
            "(select distinct count(ip) as viewcount,userid from userview group by userid) as b on a.userid = b.userid " +
            "join [user] c on a.userid=c.userid order by rate desc");
        }

        public override IEnumerable<User> FindAll(int pageIndex, int pageSize)
        {
            return this.ActiveContext.User.OrderByDescending(u => u.CreateDate).ToPagedList(pageIndex, pageSize);
        }


        public IEnumerable<User> FindMyFriend(string accountName, int pageIndex, int pageSize)
        {
            if (string.IsNullOrEmpty(accountName))
            {
                throw new ArgumentNullException("Account name");
            }
            var list = from u in this.ActiveContext.User
                       join f in this.ActiveContext.Friend
                       on u.UserID equals f.UserID
                       join d in this.ActiveContext.User
                       on f.FriendID equals d.UserID
                       where u.AccountName == accountName && f.IsConfirmed == true
                       select d;
            return list.OrderByDescending(u => u.CreateDate).ToPagedList(pageIndex, pageSize);
        }

        public override IEnumerable<User> FindAll(System.Linq.Expressions.Expression<Func<User, bool>> query, int index, int count)
        {
            if (query == null)
            {
                throw new ArgumentNullException("Query");
            }

            if (index < 0)
            {
                throw new ArgumentOutOfRangeException("Page index");
            }
            return this.ActiveContext.User.Where(query).OrderByDescending(u => u.CreateDate).ToPagedList(index, count);
        }
    }
}
